using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.Trainers.FastTree;
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using WMS_Goodsinfo.Domain;
using WMS_Goodsinfo.Infastructure.Interface;
using WMS_Goodsinfo.Infastructure.Models;

namespace WMS_Goodsinfo.Infastructure.Implement
{
    /// <summary>
    /// 预测服务实现
    /// </summary>
    public class PredictionService : IPredictionService
    {
        private readonly ProductDbContext _context;
        private readonly MLContext _mlContext;
        private readonly string _modelPath = "Models/outbound_prediction_model.zip";

        public PredictionService(ProductDbContext context)
        {
            _context = context;
            _mlContext = new MLContext(seed: 42);
        }

        /// <summary>
        /// 生成汇总数据
        /// </summary>
        public async Task<bool> GenerateSummaryDataAsync(int productId, DateTime startDate, DateTime endDate)
        {
            try
            {
                Console.WriteLine($"开始生成汇总数据 - 产品ID: {productId}, 开始日期: {startDate:yyyy-MM-dd}, 结束日期: {endDate:yyyy-MM-dd}");
                
                // 获取出入库数据 - 先获取所有该产品的数据，然后在内存中过滤
                var allInOutData = await _context.inOuts
                    .Where(i => i.ProductI_Id == productId)
                    .ToListAsync();

                // 在内存中过滤日期范围
                var inOutData = allInOutData.Where(i => 
                {
                    if (DateTime.TryParse(i.InOutTiem, out DateTime parsedDate))
                    {
                        return parsedDate.Date >= startDate.Date && parsedDate.Date <= endDate.Date;
                    }
                    return false;
                }).ToList();

                Console.WriteLine($"获取到出入库数据 {inOutData.Count} 条");

                // 按日期生成汇总数据
                for (var date = startDate; date <= endDate; date = date.AddDays(1))
                {
                    var dailyData = inOutData.Where(i => 
                        DateTime.Parse(i.InOutTiem).Date == date.Date).ToList();

                    var summary = new ProductOutboundSummary
                    {
                        ProductId = productId,
                        SummaryDate = date,
                        DailyOutboundQuantity = dailyData.Sum(i => i.OutNumbber),
                        AvgOutbound7Days = Calculate7DayAverage(inOutData, date),
                        AvgOutbound30Days = Calculate30DayAverage(inOutData, date),
                        DailyInventoryBalance = GetInventoryBalance(productId, date),
                        DayOfWeek = (int)date.DayOfWeek,
                        Month = date.Month,
                        IsHoliday = IsHoliday(date)
                    };

                    // 检查是否已存在
                    var existing = await _context.productOutboundSummaries
                        .FirstOrDefaultAsync(s => s.ProductId == productId && s.SummaryDate == date);

                    if (existing == null)
                    {
                        _context.productOutboundSummaries.Add(summary);
                    }
                }

                await _context.SaveChangesAsync();
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"生成汇总数据失败: {ex.Message}");
                Console.WriteLine($"异常详情: {ex}");
                Console.WriteLine($"堆栈跟踪: {ex.StackTrace}");
                return false;
            }
        }

        /// <summary>
        /// 生成特征数据
        /// </summary>
        public async Task<bool> GenerateFeaturesAsync(int productId, DateTime date)
        {
            try
            {
                // 获取历史汇总数据
                var summaries = await _context.productOutboundSummaries
                    .Where(s => s.ProductId == productId && s.SummaryDate <= date)
                    .OrderByDescending(s => s.SummaryDate)
                    .Take(30)
                    .ToListAsync();

                if (!summaries.Any()) return false;

                // 生成特征向量
                var featureVector = new FeatureVector
                {
                    AvgOutbound7Days = summaries.Take(7).Average(s => s.AvgOutbound7Days),
                    AvgOutbound30Days = summaries.Average(s => s.AvgOutbound30Days),
                    DailyInventoryBalance = summaries.First().DailyInventoryBalance,
                    DayOfWeek = summaries.First().DayOfWeek,
                    Month = summaries.First().Month,
                    IsHoliday = summaries.First().IsHoliday
                };

                // 保存特征数据
                var predictionFeature = new PredictionFeature
                {
                    ProductId = productId,
                    FeatureDate = date,
                    FeatureVector = JsonSerializer.Serialize(featureVector),
                    FeatureType = "Training",
                    ModelVersion = "v1.0"
                };

                _context.predictionFeatures.Add(predictionFeature);
                await _context.SaveChangesAsync();

                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"生成特征数据失败: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 训练预测模型
        /// </summary>
        public async Task<bool> TrainModelAsync(int productId)
        {
            try
            {
                // 获取训练数据
                var features = await _context.predictionFeatures
                    .Where(pf => pf.ProductId == productId && pf.FeatureType == "Training")
                    .ToListAsync();

                if (features.Count < 3) 
                {
                    Console.WriteLine($"特征数据不足，当前数量: {features.Count}，需要至少3条");
                    return false; // 需要足够的数据（临时降低要求用于测试）
                }

                Console.WriteLine($"开始训练模型，产品ID: {productId}，特征数据数量: {features.Count}");

                // 转换为ML.NET数据格式
                var trainingData = new List<PredictionInput>();
                foreach (var feature in features)
                {
                                    var featureVector = JsonSerializer.Deserialize<FeatureVector>(feature.FeatureVector);
                if (featureVector == null) continue;
                
                var summary = await _context.productOutboundSummaries
                    .FirstOrDefaultAsync(s => s.ProductId == productId && s.SummaryDate == feature.FeatureDate);

                if (summary != null)
                    {
                        trainingData.Add(new PredictionInput
                        {
                            AvgOutbound7Days = (float)featureVector.AvgOutbound7Days,
                            AvgOutbound30Days = (float)featureVector.AvgOutbound30Days,
                            DailyInventoryBalance = featureVector.DailyInventoryBalance,
                            DayOfWeek = featureVector.DayOfWeek,
                            Month = featureVector.Month,
                            IsHoliday = featureVector.IsHoliday ? 1 : 0,
                            DailyOutboundQuantity = summary.DailyOutboundQuantity
                        });
                    }
                }

                Console.WriteLine($"成功转换训练数据，数量: {trainingData.Count}");

                if (trainingData.Count == 0)
                {
                    Console.WriteLine("没有有效的训练数据，无法训练模型");
                    return false;
                }

                // 创建数据视图
                var dataView = _mlContext.Data.LoadFromEnumerable(trainingData);

                // 定义管道 - 使用更简单的线性回归算法
                var pipeline = _mlContext.Transforms.Concatenate("Features", 
                    nameof(PredictionInput.AvgOutbound7Days),
                    nameof(PredictionInput.AvgOutbound30Days),
                    nameof(PredictionInput.DailyInventoryBalance),
                    nameof(PredictionInput.DayOfWeek),
                    nameof(PredictionInput.Month),
                    nameof(PredictionInput.IsHoliday))
                    .Append(_mlContext.Regression.Trainers.Sdca(labelColumnName: "Label", maximumNumberOfIterations: 100));

                // 训练模型
                Console.WriteLine("开始训练ML.NET模型...");
                var model = pipeline.Fit(dataView);
                Console.WriteLine("模型训练完成");

                // 保存模型
                var modelDir = Path.GetDirectoryName(_modelPath);
                Console.WriteLine($"模型保存路径: {_modelPath}");
                Console.WriteLine($"模型目录: {modelDir}");
                
                if (!string.IsNullOrEmpty(modelDir) && !Directory.Exists(modelDir))
                {
                    Directory.CreateDirectory(modelDir);
                    Console.WriteLine($"已创建模型目录: {modelDir}");
                }

                _mlContext.Model.Save(model, dataView.Schema, _modelPath);
                Console.WriteLine("模型保存成功");

                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"训练模型失败: {ex.Message}");
                Console.WriteLine($"异常详情: {ex}");
                Console.WriteLine($"堆栈跟踪: {ex.StackTrace}");
                return false;
            }
        }

        /// <summary>
        /// 执行出库预测
        /// </summary>
        public async Task<int> PredictOutboundAsync(int productId, DateTime predictionDate)
        {
            try
            {
                // 生成预测特征
                await GenerateFeaturesAsync(productId, predictionDate);

                // 获取特征向量
                var feature = await _context.predictionFeatures
                    .Where(pf => pf.ProductId == productId && 
                                pf.FeatureDate == predictionDate &&
                                pf.FeatureType == "Training")
                    .FirstOrDefaultAsync();

                if (feature == null) return 0;

                // 加载模型
                if (!File.Exists(_modelPath)) return 0;

                var loadedModel = _mlContext.Model.Load(_modelPath, out var schema);
                var predictor = _mlContext.Model.CreatePredictionEngine<PredictionInput, PredictionOutput>(loadedModel);

                // 准备预测数据
                var featureVector = JsonSerializer.Deserialize<FeatureVector>(feature.FeatureVector);
                if (featureVector == null) return 0;
                
                var predictionInput = new PredictionInput
                {
                    AvgOutbound7Days = (float)featureVector.AvgOutbound7Days,
                    AvgOutbound30Days = (float)featureVector.AvgOutbound30Days,
                    DailyInventoryBalance = featureVector.DailyInventoryBalance,
                    DayOfWeek = featureVector.DayOfWeek,
                    Month = featureVector.Month,
                    IsHoliday = featureVector.IsHoliday ? 1 : 0
                };

                // 执行预测
                Console.WriteLine($"预测输入数据: AvgOutbound7Days={predictionInput.AvgOutbound7Days}, AvgOutbound30Days={predictionInput.AvgOutbound30Days}, DailyInventoryBalance={predictionInput.DailyInventoryBalance}");
                var prediction = predictor.Predict(predictionInput);
                Console.WriteLine($"原始预测结果: {prediction.PredictedOutboundQuantity}");

                var finalResult = Math.Max(0, (int)prediction.PredictedOutboundQuantity);
                Console.WriteLine($"最终预测结果: {finalResult}");
                return finalResult;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"预测失败: {ex.Message}");
                return 0;
            }
        }

        /// <summary>
        /// 获取预测历史
        /// </summary>
        public async Task<List<PredictionFeature>> GetPredictionHistoryAsync(int productId, DateTime startDate, DateTime endDate)
        {
            return await _context.predictionFeatures
                .Where(pf => pf.ProductId == productId && 
                            pf.FeatureDate >= startDate && 
                            pf.FeatureDate <= endDate)
                .OrderByDescending(pf => pf.FeatureDate)
                .ToListAsync();
        }

        #region 私有方法

        private decimal Calculate7DayAverage(List<InOut> data, DateTime date)
        {
            var startDate = date.AddDays(-7);
            var endDate = date.AddDays(-1);
            
            var weekData = data.Where(i => 
            {
                if (DateTime.TryParse(i.InOutTiem, out DateTime parsedDate))
                {
                    return parsedDate.Date >= startDate.Date && 
                           parsedDate.Date <= endDate.Date &&
                           i.OutNumbber > 0;
                }
                return false;
            }).ToList();

            return weekData.Any() ? (decimal)weekData.Average(i => i.OutNumbber) : 0;
        }

        private decimal Calculate30DayAverage(List<InOut> data, DateTime date)
        {
            var startDate = date.AddDays(-30);
            var endDate = date.AddDays(-1);
            
            var monthData = data.Where(i => 
            {
                if (DateTime.TryParse(i.InOutTiem, out DateTime parsedDate))
                {
                    return parsedDate.Date >= startDate.Date && 
                           parsedDate.Date <= endDate.Date &&
                           i.OutNumbber > 0;
                }
                return false;
            }).ToList();

            return monthData.Any() ? (decimal)monthData.Average(i => i.OutNumbber) : 0;
        }

        private int GetInventoryBalance(int productId, DateTime date)
        {
            // 从商品表获取当前库存
            var product = _context.product_Table.FirstOrDefault(p => p.Id == productId);
            return product?.Current_Inventory ?? 0;
        }

        private bool IsHoliday(DateTime date)
        {
            // 简单的节假日判断逻辑
            var dayOfWeek = date.DayOfWeek;
            return dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday;
        }

        #endregion
    }
} 